﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using Map;
using Map_Creator.MapInfo;
using Map_Creator.RedoUndo;
using Map_Creator.RedoUndo.Actions;
using Microsoft.Xna.Framework;

namespace Map_Creator.AnimatedTileEditor
{
    public partial class AnimationStrip : XNA.GraphicsDeviceControl
    {
        private List<TileStruct>  tiles = new List<TileStruct>();
        private TileSet tileSet;
        private TileSetControl tileSetControl;
        private IRedoUndo actionHandler;

        public AnimationStrip()
        {
            InitializeComponent();
        }

        public AnimationStrip(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
        }

        public void Initialize(AnimatedTileStruct animatedTile, TileSet set,TileSetControl control, IRedoUndo redoUndo)
        {
            tileSet = set;
            tileSetControl = control;
            tileSetControl.MouseDoubleClick +=tileSetControl_MouseDoubleClick;
            actionHandler = redoUndo;
            if (animatedTile == null) return;
            foreach (var frame in animatedTile.Frames)
            {
                tiles.Add(frame);
            }
        }

        private void tileSetControl_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Insert(tiles.Count, tileSetControl.GetSelectedTile());
            Invalidate();
        }

        protected override void Draw(PaintEventArgs e)
        {
            GraphicsDevice.Clear(new Color(BackColor.R, BackColor.G, BackColor.B));
            // no back buffer is used so we need to paint it all over again each call
            xnaGraphics.Begin();

            var tileSize = tileSet.AssociatedMap.TileSize;
            var tilesSize = tileSet.TilesSize;
            var position = new Vector2(10,0);
            foreach (var tileStruct in tiles)
            {
                var dest = new Rectangle((int) position.X, (int) position.Y, tileSize, tileSize);
                xnaGraphics.Draw(tileSet.TilesImage, dest,
                                 new Rectangle(
                                     (tileStruct.Value % tilesSize.X) * tileSize, 
                                     (tileStruct.Value/tilesSize.X)*tileSize, 
                                     tileSize,tileSize), 
                                     Color.White);
                xnaGraphics.DrawRectangle(dest,Color.Black);
                // 10 is spacing between tiles
                position.X += tileSize + 10;
            }

            xnaGraphics.End();
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            switch (e.Button)
            {
                case MouseButtons.Left:
                    LeftClicked(e);
                    break;
                case MouseButtons.Right:
                    RightClicked(e);
                    break;
            }
        }

        private void LeftClicked(MouseEventArgs e)
        {
            var position = e.Location;
            position.X = MathEx.Clamp(position.X, 0, Width - 1);
            position.Y = MathEx.Clamp(position.Y, 0, Height - 1);

            var isBetween = false;
            var tilePosition = position.X/(tileSet.AssociatedMap.TileSize + 10);
            if (position.X - (tilePosition*(tileSet.AssociatedMap.TileSize + 10)) < 10)
                isBetween = true;

            if (tiles.Count > tilePosition)
            {
                if (isBetween)
                    Insert(tilePosition, tileSetControl.GetSelectedTile());
                else
                    Replace(tilePosition, tileSetControl.GetSelectedTile());
            }
            else
            {
                Insert(tiles.Count,tileSetControl.GetSelectedTile());
            }
            Invalidate();
        }

        void RightClicked(MouseEventArgs e)
        {
            var position = e.Location;
            position.X = MathEx.Clamp(position.X, 0, Width - 1);
            position.Y = MathEx.Clamp(position.Y, 0, Height - 1);

            var isBetween = false;
            var tilePosition = position.X / (tileSet.AssociatedMap.TileSize + 10);

            if (tiles.Count <= tilePosition) return;

            if (position.X - (tilePosition * (tileSet.AssociatedMap.TileSize + 10)) < 10)
                isBetween = true;

            if (isBetween) return;
            
            Remove(tilePosition);
            Invalidate();
        }

        private void Replace(int pos, TileStruct tile)
        {
            var action = new ListReplaceAction(tiles, pos, tile);
            actionHandler.AddActionAndExecute(action);
        }
        private void Insert(int pos, TileStruct tile)
        {
            var action = new ListInsertAction(tiles, pos, tile);
            actionHandler.AddActionAndExecute(action);

        }
        void Remove(int pos)
        {
            var action = new ListRemoveAction(tiles, pos);
            actionHandler.AddActionAndExecute(action);
        }

        public AnimatedTile GetAnimatedTile()
        {
            var animatedTile = new AnimatedTile
                                   {
                                       Frames = tiles.ToArray(), 
                                       TileSetIndex = (short) tileSet.Index
                                   };
            return animatedTile;
        }
    }
}